package com.ctshk.rpc.starvip.util;

import com.ctshk.rpc.starvip.factory.StarVipReqProvider;
import com.ibm.mq.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.Hashtable;

/**
 * @BelongsProject: ctshk-cloud
 * @BelongsPackage: com.ctshk.rpc.starvip.util
 * @Author: hef
 * @CreateTime: 2021-04-12 11:46
 * @Description: 描述
 */
@Component
public class IBMMqUtil {

/*    static String hostname = "10.130.101.111";                                                                    //MQ 服务器的主机名或 IP 地址
    static String channel = "SYSTEM.ADMIN.SVRCONN";                                                //MQ 服务器连接通道
    static String queueManager = "S99_QM3";                                                            //MQ 队列管理器的名称
    static String sendQueue = "S99_CRM_R_OUT_H_GROUP";                                        //MQ 队列管理器中发送队列 High
    static String recvQueue = "S99_CRM_L_IN_H_GROUP";                                    //MQ 队列管理器中接收队列 High

    static String replyToQueueManagerName = "E88_CRM_QM1";                            //发送的消息必须定义的消息头
    static String replyToQueueName = "S99_CRM_R_OUT_H_S99_QM3";                        //High
    static int expiry = 10000;                                                    //发送的消息必须定义的消息头，指明消息的最大存活时间（单位 0.1 秒）
    static int port = 15003;                                                                                                //MQ 服务器的端口
    //int ccsid = 1208;																								//字符集编码
    static int fetchMaxTimes = 5;                                                                                    //取返回消息时的重试次数
    static int intervalTime = 20000;*/

    static String hostname;                                                                    //MQ 服务器的主机名或 IP 地址
    static String channel;                                                //MQ 服务器连接通道
    static String queueManager;                                                            //MQ 队列管理器的名称
    static String sendQueue;                                        //MQ 队列管理器中发送队列 High
    static String recvQueue;                                    //MQ 队列管理器中接收队列 High

    static String replyToQueueManagerName;                            //发送的消息必须定义的消息头
    static String replyToQueueName;                        //High
    static int expiry;                                                    //发送的消息必须定义的消息头，指明消息的最大存活时间（单位 0.1 秒）
    static int port;                                                                                                //MQ 服务器的端口	    //字符集编码
    static int fetchMaxTimes;                                                                                    //取返回消息时的重试次数
    static int intervalTime;
    static int ccsid = 1386;

    @Value("${star-vip.mq.hostname}")
    public void setHostname(String hostname) {
        IBMMqUtil.hostname = hostname;
    }

    @Value("${star-vip.mq.channel}")
    public void setChannel(String channel) {
        IBMMqUtil.channel = channel;
    }

    @Value("${star-vip.mq.queue_manager}")
    public void setQueueManager(String queueManager) {
        IBMMqUtil.queueManager = queueManager;
    }

    @Value("${star-vip.mq.send_queue}")
    public void setSendQueue(String sendQueue) {
        IBMMqUtil.sendQueue = sendQueue;
    }

    @Value("${star-vip.mq.recv_queue}")
    public void setRecvQueue(String recvQueue) {
        IBMMqUtil.recvQueue = recvQueue;
    }

    @Value("${star-vip.mq.reply_to_queue_manager_name}")
    public void setReplyToQueueManagerName(String replyToQueueManagerName) {
        IBMMqUtil.replyToQueueManagerName = replyToQueueManagerName;
    }

    @Value("${star-vip.mq.reply_to_queue_name}")
    public void setReplyToQueueName(String replyToQueueName) {
        IBMMqUtil.replyToQueueName = replyToQueueName;
    }

    @Value("${star-vip.mq.expiry}")
    public void setExpiry(Integer expiry) {
        IBMMqUtil.expiry = expiry;
    }

    @Value("${star-vip.mq.port}")
    public void setPort(Integer port) {
        IBMMqUtil.port = port;
    }

    @Value("${star-vip.mq.port}")
    public void setFetchMaxTimes(Integer fetchMaxTimes) {
        IBMMqUtil.fetchMaxTimes = fetchMaxTimes;
    }

    @Value("${star-vip.mq.interval_time}")
    public void setIntervalTime(Integer intervalTime) {
        IBMMqUtil.intervalTime = intervalTime;
    }

    public static String send(StarVipReqProvider provider) throws Exception {
        JaxbUtil jaxbUtil = new JaxbUtil(provider.produce().getClass());
        String sendMessage = jaxbUtil.toXml(provider.produce(), "UTF-8");
        //定义连接队列管理器的各项参数
        Hashtable properties = new Hashtable();
        properties.put("hostname", hostname);
        properties.put("channel", channel);
        properties.put("CCSID", ccsid);
        properties.put("port", port);
        MQQueueManager qManager = new MQQueueManager(queueManager, properties);
        //发送消息
        int openOptions = MQC.MQOO_OUTPUT | MQC.MQOO_FAIL_IF_QUIESCING;
        MQQueue sQueue = qManager.accessQueue(sendQueue, openOptions);

        MQPutMessageOptions pmo = new MQPutMessageOptions();
        MQMessage send = new MQMessage();
        send.replyToQueueManagerName = replyToQueueManagerName; //定义的消息头
        send.replyToQueueName = replyToQueueName; //定义的消息头
        send.expiry = expiry; //定义的消息头
        send.write(sendMessage.getBytes("utf-8"));
        sQueue.put(send, pmo);
        long beginTime = System.currentTimeMillis();
        sQueue.close();
        System.out.println("发送的消息为：" + sendMessage);
        //System.out.println("发送的消息为1111：" + new String(sendMessage.getBytes()));


        /***************************************************************************************/


        //接收消息

        openOptions = MQC.MQOO_INQUIRE + MQC.MQOO_FAIL_IF_QUIESCING
                + MQC.MQOO_INPUT_SHARED;
        MQQueue rQueue = qManager.accessQueue(recvQueue, openOptions);
        MQException.logExclude(new Integer(2033));
        MQGetMessageOptions getOptions = new MQGetMessageOptions();
        getOptions.options = MQC.MQGMO_WAIT; //取消息时等待
        getOptions.waitInterval = intervalTime; //最大等待时间

        MQMessage recvMsg = new MQMessage();
        recvMsg.correlationId = send.messageId; //这里是关键，要保证接收的消息相关编号与发送的消息编号是一致的，这样就不会取到别的消息
        send.clearMessage();

        boolean received = false;
        int fetchCount = 0;
        while (!received && fetchCount < fetchMaxTimes) {
            try {
                fetchCount++;
                System.out.println("取消息次数：" + fetchCount);
                rQueue.get(recvMsg, getOptions);
                received = true; //置已接收标记为 true
            } catch (MQException me) //发生 MQ 相关的异常
            {
                if (me.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE) //如果错误代码为没有消息，这并非错误，可能是消息并未到达
                {
                    received = false;
                } else //MQ 异常
                {
                    recvMsg.clearMessage();
                    rQueue.close();
                    qManager.disconnect();

                    received = false;
                    System.out.println("MQ 错误信息：" + me.toString());
                    break; //跳出循环
                }
            } catch (Exception ex) {
                recvMsg.clearMessage();
                rQueue.close();
                qManager.disconnect();

                received = false;
                System.out.println("错误信息：" + ex.toString());
                break;
            }
        }

        String returnStr = null;
        if (received) {
            int index = recvMsg.getMessageLength();
            System.out.println("接收的消息长度为：" + index);
//            String message = recvMsg.readStringOfByteLength(index);
            byte[] bytes = new byte[index];
            recvMsg.readFully(bytes);
            returnStr = new String(bytes, StandardCharsets.UTF_8);
            System.out.println("==============================returnStr:" + returnStr);
        } else {
            System.out.println("并未接到消息！！");
        }
        recvMsg.clearMessage();
        rQueue.close();
        qManager.disconnect();
        //System.out.println("str:" + returnStr);
        //out.println(returnStr);
        //out.flush();
        return returnStr;
    }

    // 测试星赏会接口
    public static String sendTest(String sendMessage) throws Exception {
        /*JaxbUtil jaxbUtil = new JaxbUtil(provider.produce().getClass());
        String sendMessage = jaxbUtil.toXml(provider.produce(), "UTF-8");*/
        //定义连接队列管理器的各项参数
        Hashtable properties = new Hashtable();
        properties.put("hostname", hostname);
        properties.put("channel", channel);
        properties.put("CCSID", ccsid);
        properties.put("port", port);
        MQQueueManager qManager = new MQQueueManager(queueManager, properties);
        //发送消息
        int openOptions = MQC.MQOO_OUTPUT | MQC.MQOO_FAIL_IF_QUIESCING;
        MQQueue sQueue = qManager.accessQueue(sendQueue, openOptions);

        MQPutMessageOptions pmo = new MQPutMessageOptions();
        MQMessage send = new MQMessage();
        send.replyToQueueManagerName = replyToQueueManagerName; //定义的消息头
        send.replyToQueueName = replyToQueueName; //定义的消息头
        send.expiry = expiry; //定义的消息头
        send.write(sendMessage.getBytes("utf-8"));
        sQueue.put(send, pmo);
        long beginTime = System.currentTimeMillis();
        sQueue.close();
        System.out.println("发送的消息为：" + sendMessage);
        //System.out.println("发送的消息为1111：" + new String(sendMessage.getBytes()));


        /***************************************************************************************/


        //接收消息

        openOptions = MQC.MQOO_INQUIRE + MQC.MQOO_FAIL_IF_QUIESCING
                + MQC.MQOO_INPUT_SHARED;
        MQQueue rQueue = qManager.accessQueue(recvQueue, openOptions);
        MQException.logExclude(new Integer(2033));
        MQGetMessageOptions getOptions = new MQGetMessageOptions();
        getOptions.options = MQC.MQGMO_WAIT; //取消息时等待
        getOptions.waitInterval = intervalTime; //最大等待时间

        MQMessage recvMsg = new MQMessage();
        recvMsg.correlationId = send.messageId; //这里是关键，要保证接收的消息相关编号与发送的消息编号是一致的，这样就不会取到别的消息
        send.clearMessage();

        boolean received = false;
        int fetchCount = 0;
        while (!received && fetchCount < fetchMaxTimes) {
            try {
                fetchCount++;
                System.out.println("取消息次数：" + fetchCount);
                rQueue.get(recvMsg, getOptions);
                received = true; //置已接收标记为 true
            } catch (MQException me) //发生 MQ 相关的异常
            {
                if (me.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE) //如果错误代码为没有消息，这并非错误，可能是消息并未到达
                {
                    received = false;
                } else //MQ 异常
                {
                    recvMsg.clearMessage();
                    rQueue.close();
                    qManager.disconnect();

                    received = false;
                    System.out.println("MQ 错误信息：" + me.toString());
                    break; //跳出循环
                }
            } catch (Exception ex) {
                recvMsg.clearMessage();
                rQueue.close();
                qManager.disconnect();

                received = false;
                System.out.println("错误信息：" + ex.toString());
                break;
            }
        }

        String returnStr = null;
        if (received) {
            int index = recvMsg.getMessageLength();
            System.out.println("接收的消息长度为：" + index);
//            String message = recvMsg.readStringOfByteLength(index);
            byte[] bytes = new byte[index];
            recvMsg.readFully(bytes);
            returnStr = new String(bytes, StandardCharsets.UTF_8);
            System.out.println("==============================returnStr:" + returnStr);
        } else {
            System.out.println("并未接到消息！！");
        }
        recvMsg.clearMessage();
        rQueue.close();
        qManager.disconnect();
        //System.out.println("str:" + returnStr);
        //out.println(returnStr);
        //out.flush();
        return returnStr;
    }

    public static void main(String[] args) {
        System.out.println(StandardCharsets.UTF_8);
    }
}
